<template>
	<div class="component-upload-image">
		<el-upload
			:action="action"
			:headers="headers"
			:multiple="limit === 1 ? false : true"
			:on-preview="onPreviewUpload"
			:on-remove="onRemoveUpload"
			:on-success="onUploadSuccess"
			:on-error="onErrorUpload"
			:on-exceed="onExceedUpload"
			:before-upload="onBeforeUpload"
			list-type="picture-card"
			:file-list="state.fileList"
			:disabled="disabled"
			:limit="limit"
			ref="imageUploadRef"
			:class="{ fileComputed, isDelete }"
		>
			<el-icon>
				<ele-UploadFilled />
			</el-icon>
			<template #tip v-if="isShowTip">
				<el-alert
					:title="`上传图片支持 ${fileType.join(' / ')} 格式，单张图片大小不超过 ${fileSize}MB，${
						imageSize ? '建议图片尺寸为 ' + imageSize : ''
					}，且图片数量不超过 ${limit} 张`"
					type="info"
					show-icon
					:closable="false"
					style="line-height: 16px; margin-top: 5px"
				/>
			</template>
		</el-upload>
		<el-image-viewer v-if="state.dialogVisible" :initial-index="state.lookNum" @close="state.dialogVisible = false" :url-list="fileUrlList" />
	</div>
</template>

<script setup lang="ts" name="imageUpload">
import { reactive, ref, computed, watch } from 'vue';
import { ElMessage, ElLoading } from 'element-plus';
import { Session } from '/@/utils/storage';

// 定义父组件传过来的值
const props = defineProps({
	action: {
		type: String,
		default: '',
	},
	headers: {
		type: Object,
		default: () => {
			return {
				token: Session.get('token'),
			};
		},
	},
	// 图片数量限制
	limit: {
		type: Number,
		default: 1,
	},
	// 图片类型, 例如['png', 'jpg', 'jpeg']
	fileType: {
		type: Array,
		default: () => ['png', 'jpg', 'jpeg', 'webp', 'bmp'],
	},
	// 大小限制(MB)
	fileSize: {
		type: Number,
		default: 1,
	},
	imageSize: {
		type: String,
		default: '',
	},
	modelValue: {
		type: String,
		default: '',
	},
	disabled: {
		type: Boolean,
		default: false,
	},
	isDelete: {
		type: Boolean,
		default: false,
	},
	// 是否显示提示
	isShowTip: {
		type: Boolean,
		default: true,
	},
});

// 定义子组件向父组件传值/事件
const emit = defineEmits(['update:modelValue']);

const state: any = reactive({
	number: 0,
	uploadList: [],
	fileList: [],
	dialogVisible: false,
	lookValue: '',
	lookNum: 0,
});

const uploadLoading = ref();
const imageUploadRef = ref();

const fileComputed = computed(() => {
	return state.fileList.length >= props.limit;
});

const fileUrlList = computed(() => {
	return state.fileList.map((item: any) => item.url);
});

watch(
	() => props.modelValue,
	(val) => {
		if (val) {
			// 首先将值转为数组
			const list = Array.isArray(val) ? val : props.modelValue.split(',');
			state.number = list.length
			// 然后将数组转为对象数组
			state.fileList = list.map((item, index) => {
				return { uid: item.uid || new Date().getTime() + index + 1, name: item, url: item, upload: true };
			});
		} else {
			state.number = 0
			state.fileList = [];
			return [];
		}
	},
	{
		deep: true,
		immediate: true,
	}
);
/********** 点击事件(on开头) **********/
// 图片预览
const onPreviewUpload = (file: any) => {
	state.dialogVisible = true;
	state.lookNum = state.fileList.findIndex((item: any) => item.url == file.url);
};
// 删除图片
const onRemoveUpload = () => {
	emit('update:modelValue', state.fileList.length ? listToString(state.fileList) : '');
};
// 上传成功回调
const onUploadSuccess = (res: any, file: any, fileList: any) => {
	if (res.msg == 'ok') {
		const info = res.data.info;
		let fileLists = fileList;
		fileLists.forEach((element: any) => {
			if (element.uid == file.uid) {
				element.url = info.show_url;
				element.upload = true;
			}
		});
		state.uploadList = fileLists.filter((item: any) => item.upload);
		uploadedSuccessfully();
	} else {
		const fileFindIndex = state.fileList.findIndex((item: any) => item.uid == 1);
		state.fileList.splice(fileFindIndex, 1);
		if (state.number) {
			state.number--;
		}
		uploadLoading.value.close();
		ElMessage.warning(res.msg);
		imageUploadRef.value.handleRemove(file);
		uploadedSuccessfully();
	}
};
// 上传失败
const onErrorUpload = () => {
	ElMessage.warning('上传图片失败，请重试');
	uploadLoading.value.close();
};
// 上传前校验
const onBeforeUpload = (file: any) => {
	let isImg = false;
	if (props.fileType.length) {
		let fileExtension = '';
		if (file.name.lastIndexOf('.') > -1) {
			fileExtension = file.name.slice(file.name.lastIndexOf('.') + 1);
		}
		isImg = props.fileType.some((type: any) => {
			if (file.type.indexOf(type) > -1) return true;
			if (fileExtension && fileExtension.indexOf(type) > -1) return true;
			return false;
		});
	} else {
		isImg = file.type.indexOf('image') > -1;
	}

	if (!isImg) {
		ElMessage.error(`图片格式不正确, 请上传${props.fileType.join('/')}格式!`);
		return false;
	}
	if (props.fileSize) {
		const isLt = file.size / 1024 / 1024 < props.fileSize;
		if (!isLt) {
			ElMessage.error(`上传图片大小不能超过 ${props.fileSize} MB!`);
			return false;
		}
	}
	state.fileList.push(file);
	uploadLoading.value = ElLoading.service({
		lock: true,
		text: '正在上传图片，请稍候...',
		spinner: 'el-icon-loading',
		background: 'rgba(0, 0, 0, 0.7)',
	});
	state.number++;
};
const onExceedUpload = (files: any, uploadFiles: any) => {
	ElMessage.warning(`当前限制选择 ${props.limit} 张图片，本次选择了 ${files.length} 张图片，共选择了 ${files.length + uploadFiles.length} 张图片`);
};
// 上传结束处理
const uploadedSuccessfully = () => {
	if (state.number > 0 && state.uploadList.length === state.number) {
		state.fileList = state.uploadList;
		state.uploadList = [];
		state.number = 0;
		emit('update:modelValue', listToString(state.fileList));
		uploadLoading.value.close();
	}
};
// 对象转成指定字符串分隔
const listToString = (list: Array<any>, separator: string = ',') => {
	let strs = '';
	for (let i in list) {
		if (list[i].url) {
			strs += list[i].url + separator;
		}
	}
	return strs != '' ? strs.substr(0, strs.length - 1) : '';
};
</script>

<style lang="scss">
.component-upload-image {
	.fileComputed {
		.el-upload--picture-card {
			display: none;
		}
	}
	.isDelete {
		.el-upload-list {
			.el-upload-list__item {
				.el-upload-list__item-delete {
					display: none;
				}
			}
		}
		.el-upload--picture-card {
			display: none;
		}
	}
}
</style>
